import React, { Component, createRef } from "react";
import { Spine } from "./spine";
import {
  Card,
  CardContent,
  IconButton,
  FormControlLabel,
  Switch,
  Slider,
  Box,
  Dialog,
  DialogTitle,
  DialogContent,
  TableContainer,
  Table,
  TableBody,
  TableHead,
  TableRow,
  TableCell,
  Backdrop,
  LinearProgress,
  Select,
  MenuItem,
  FormControl,
  InputLabel,
  Tooltip,
  Grid,
} from "@material-ui/core";
import {
  RefreshOutlined,
  GetAppOutlined,
  FullscreenOutlined,
  FullscreenExitOutlined,
  InfoOutlined,
} from "@material-ui/icons";
import { ColorPicker } from "material-ui-color";
import Typography from "@material-ui/core/Typography";
import parser from "../utils/skel";
import isMobile from "../utils/isMobile";
import { getBlobUrl } from "../utils/getBlobUrl";
export default class SpineViewer extends Component {
  constructor() {
    super();
    const spineData = JSON.parse(
      document.getElementById("SPINEDATA").innerHTML
    );
    this.spineData = spineData.skin;
    this.name = spineData.name;
    this.prefix = spineData.prefix;
    this.skinList = Object.keys(this.spineData);
    // Object.keys(spineData);
    // console.log(spineData);
    this.handleColorChange = this.handleColorChange.bind(this);
    this.reset = this.reset.bind(this);
    this.handleSpeed = this.handleSpeed.bind(this);
    this.onSkinChange = this.onSkinChange.bind(this);
    this.onModelChange = this.onModelChange.bind(this);
    this.onLoopChange = this.onLoopChange.bind(this);
    this.onAnimationChange = this.onAnimationChange.bind(this);
    this.onClickFullScreen = this.onClickFullScreen.bind(this);
    this.encode = this.encode.bind(this);
    this.animationsData = [];
    this.state = {
      color: "ffffff",
      speed: 1,
      animations: [],
      animation: "",
      loop: false,
      openInfo: false,
      skin: this.skinList[0],
      modelList: Object.keys(this.spineData[this.skinList[0]]),
      model: Object.keys(this.spineData[this.skinList[0]])[0],
      loading: true,
      json: {},
      fullscreen: false,
      scale: 0.3,
      building: false,
      progress: 0,
    };
    this.spineRef = createRef();
    this.rootRef = createRef();
    this.loopRef = createRef();
    this.isMobile = isMobile();
  }
  handleColorChange(color) {
    // console.log(color);
    if (color.hex !== this.state.color) {
      this.setState({
        color: color.hex,
      });
      if (!this.state.loading) {
        this.spineRef.current.updateColor(
          color.rgb[0],
          color.rgb[1],
          color.rgb[2],
          color.alpha
        );
      }
    }
  }
  reset() {
    if (!this.state.loading) {
      this.spineRef.current.reset();
    }
  }
  handleSpeed(_, v) {
    if (v !== this.state.speed) {
      this.setState({ speed: v });
      if (!this.state.loading) {
        this.spineRef.current.updateSpeed(v);
      }
    }
  }
  onSkinChange(v) {
    const value = v.target.value;
    this.setState({
      skin: value,
      modelList: Object.keys(this.spineData[value]),
      model: Object.keys(this.spineData[value])[0],
      animations: [],
      animation: "",
      loading: true,
    });
    this.loadData(value, Object.keys(this.spineData[value])[0]);
  }
  onModelChange(v) {
    const value = v.target.value;
    this.setState({
      model: value,
      animations: [],
      animation: "",
      loading: true,
    });
    this.loadData(this.state.skin, value);
  }
  onLoopChange(e) {
    // console.log(e.target.checked);
    this.setState({ loop: e.target.checked });
    if (!this.state.loading && !this.state.building) {
      this.spineRef.current.updateAnimation(
        this.state.animation,
        e.target.checked
      );
    }
  }
  onAnimationChange(v) {
    const value = v.target.value;
    this.setState({ animation: value });
    if (!this.state.loading) {
      this.spineRef.current.updateAnimation(value, this.state.loop);
    }
  }
  onClickFullScreen() {
    if (!this.state.fullscreen) {
      // console.log(this.rootRef.current);
      // // console.log();
      // this.rootRef.current.requestFullscreen().then(() => {
      // this.setState({ fullscreen: true });
      // });
      this.setState({ fullscreen: true, scale: 1 });
    } else {
      this.setState({ fullscreen: false, scale: 0.3 });
      // document.exitFullscreen();
    }
  }
  componentDidMount() {
    // this.rootRef.current.addEventListener("fullscreenchange", () => {
    //   if (document.fullscreenElement) {
    //     this.setState({
    //       scale:
    //         Math.min(
    //           document.documentElement.clientHeight - 40,
    //           document.documentElement.clientWidth - 314
    //         ) / 1000,
    //     });
    //   } else {
    //     this.setState({
    //       fullscreen: false,
    //       scale: 0.3,
    //     });
    //   }
    // });
    this.loadData(
      this.skinList[0],
      Object.keys(this.spineData[this.skinList[0]])[0]
    );
  }
  loadData(skin, model) {
    parser(this.prefix + this.spineData[skin][model].file + ".skel").then(
      (data) => {
        // console.log(data);
        const animations = Object.keys(data.animations);
        this.setState({
          json: data,
          animations: animations,
          animation: animations[0],
        });
        this.spineRef.current.loadWidget(
          data,
          this.prefix + this.spineData[skin][model].file + ".atlas",
          animations[0],
          this.state.color,
          this.state.loop,
          this.spineData[this.state.skin][this.state.model].skin || "default",
          this.state.speed,
          (aniData) => {
            this.animationsData = aniData;
            this.setState({ loading: false });
          }
        );
      }
    );
  }
  encode() {
    this.setState({ building: true });
    getBlobUrl("http://static.prts.wiki/spine/js/gif.worker.js").then((url) => {
      this.spineRef.current.ensureEncoder(
        // "/gif.worker.js",
        url,
        `${this.name}-${this.state.skin}-${this.state.model}-${this.state.animation}-x${this.state.speed}.gif`,
        (v) => {
          this.setState({ progress: v * 100 });
        },
        () => {
          this.setState({ building: false, progress: 0 });
        }
      );
      this.spineRef.current.buildGif(this.state.animation);
    });
  }
  render() {
    return (
      <div style={{ width: "fit-content", position: "relative" }}>
        <Card
          ref={this.rootRef}
          style={{ display: "flex", flexWrap: "wrap", width: "fit-content" }}
        >
          <CardContent style={{ width: 300 }}>
            <FormControl
              variant="outlined"
              style={{ width: "100%", margin: "0.3rem 0" }}
              size={"small"}
            >
              <InputLabel id="skin-select-outlined-label">皮肤</InputLabel>
              <Select
                labelId="skin-select-outlined-label"
                value={this.state.skin}
                onChange={this.onSkinChange}
                label="皮肤"
                native={this.isMobile}
              >
                {this.isMobile
                  ? this.skinList.map((v) => (
                      <option value={v} key={v}>
                        {v}
                      </option>
                    ))
                  : this.skinList.map((v) => (
                      <MenuItem value={v} key={v}>
                        {v}
                      </MenuItem>
                    ))}
              </Select>
            </FormControl>
            <FormControl
              variant="outlined"
              style={{ width: "100%", margin: "0.3rem 0" }}
              size={"small"}
            >
              <InputLabel id="model-select-outlined-label">模型</InputLabel>
              <Select
                labelId="model-select-outlined-label"
                value={this.state.model}
                onChange={this.onModelChange}
                label="模型"
                native={this.isMobile}
              >
                {this.isMobile
                  ? this.state.modelList.map((v) => (
                      <option value={v} key={v}>
                        {v}
                      </option>
                    ))
                  : this.state.modelList.map((v) => (
                      <MenuItem value={v} key={v}>
                        {v}
                      </MenuItem>
                    ))}
              </Select>
            </FormControl>
            <FormControl
              variant="outlined"
              style={{ width: "100%", margin: "0.3rem 0" }}
              size={"small"}
            >
              <InputLabel id="ani-select-outlined-label">动画</InputLabel>
              <Select
                labelId="ani-select-outlined-label"
                value={this.state.animation}
                onChange={this.onAnimationChange}
                label="动画"
                native={this.isMobile}
              >
                {this.isMobile
                  ? this.state.animations.map((v) => (
                      <option value={v} key={v}>
                        {v}
                      </option>
                    ))
                  : this.state.animations.map((v) => (
                      <MenuItem value={v} key={v}>
                        {v}
                      </MenuItem>
                    ))}
              </Select>
            </FormControl>
            <Grid container justify="space-around">
              <FormControlLabel
                ref={this.loopRef}
                control={
                  <Switch
                    value={this.state.loop}
                    onChange={this.onLoopChange}
                  />
                }
                label="循环播放"
                labelPlacement="end"
              />
              <FormControlLabel
                control={
                  <ColorPicker
                    // defaultValue="#000"
                    // disableAlpha
                    hideTextfield
                    value={"#" + this.state.color}
                    onChange={this.handleColorChange}
                  ></ColorPicker>
                }
                label="背景颜色"
                labelPlacement="end"
              />
            </Grid>
            <Typography component="div" style={{ margin: "4px 0" }}>
              <Box textAlign="left">播放速度</Box>
            </Typography>
            <Slider
              aria-labelledby="continuous-slider"
              step={0.1}
              min={0.1}
              max={2}
              // marks={true}
              defaultValue={1}
              value={this.speed}
              valueLabelDisplay="auto"
              onChange={this.handleSpeed}
            />
            <Grid container justify="center">
              {!this.isMobile ? (
                <Tooltip title="实验性GIF导出" aria-label="实验性GIF导出">
                  <IconButton onClick={this.encode}>
                    <GetAppOutlined />
                  </IconButton>
                </Tooltip>
              ) : null}
              <Tooltip title="重置位置" aria-label="重置位置">
                <IconButton onClick={this.reset}>
                  <RefreshOutlined />
                </IconButton>
              </Tooltip>
              {!this.isMobile ? (
                <Tooltip
                  title={this.state.fullscreen ? "缩小" : "放大"}
                  aria-label={this.state.fullscreen ? "缩小" : "放大"}
                >
                  <IconButton onClick={this.onClickFullScreen}>
                    {this.state.fullscreen ? (
                      <FullscreenExitOutlined />
                    ) : (
                      <FullscreenOutlined />
                    )}
                  </IconButton>
                </Tooltip>
              ) : null}
              <Tooltip title="动画长度" aria-label="动画长度">
                <IconButton
                  onClick={() => {
                    this.setState({ openInfo: true });
                  }}
                >
                  <InfoOutlined></InfoOutlined>
                </IconButton>
              </Tooltip>
            </Grid>
          </CardContent>
          <CardContent>
            <Spine
              ref={this.spineRef}
              scale={this.state.scale}
              loading={this.state.loading}
            ></Spine>
          </CardContent>
        </Card>
        <Backdrop
          open={this.state.building}
          style={{
            zIndex: 2,
            right: "inherit",
            bottom: "inherit",
            position: "absolute",
            width: "100%",
            height: "100%",
          }}
        >
          <Card style={{ width: "70%" }}>
            <CardContent>
              <div style={{ marginBottom: 16 }}>
                正在导出 {this.name}-{this.state.skin}-{this.state.model}-
                {this.state.animation}-x{this.state.speed}.gif
              </div>
              <LinearProgress
                value={this.state.progress}
                variant="determinate"
              />
            </CardContent>
          </Card>
        </Backdrop>
        <Dialog
          open={this.state.openInfo}
          onClose={() => {
            this.setState({ openInfo: false });
          }}
        >
          <DialogTitle>
            {this.name} - {this.state.skin} - {this.state.model}
          </DialogTitle>
          <DialogContent>
            <TableContainer>
              <Table>
                <TableHead>
                  <TableRow>
                    <TableCell>动画</TableCell>
                    <TableCell>持续时间(s)</TableCell>
                    <TableCell>帧数(30/s)</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {this.animationsData.map((r) => (
                    <TableRow key={r.name}>
                      <TableCell>{r.name}</TableCell>
                      <TableCell>{r.duration}</TableCell>
                      <TableCell>{Math.round(r.duration * 30)}</TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </TableContainer>
          </DialogContent>
        </Dialog>
      </div>
    );
  }
}
